package com.csthink.auditlog.domain;

import com.csthink.auditlog.enums.CategoryEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.google.common.base.Enums;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * @author <a href="mailto:security.2009@live.cn">Mars</a>
 * @since 2023-09-12
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuditLog {

    private String id;

    /**
     * recorded by (cci-web | cci-api | cci-op)
     */
    private String source;

    /**
     * operator info
     */
    private String operatorType;

    private String operatorId;

    private String operatorInfo;

    private String operatorRole;

    private String remoteAddr;

    /**
     * log details
     */
    private String url;

    private String category;

    private String action;

    private String subAction;

    private String detail;


    private String accountId;

    private String accountInfo;

    private List<Change> changes;

    private boolean writeRecord = true;

    private String traceId;

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date logTime;

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date opStartTime;

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date opEndTime;

    private Date createTime;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getOperatorType() {
        return operatorType;
    }

    public void setOperatorType(String operatorType) {
        this.operatorType = operatorType;
    }

    public String getOperatorId() {
        return operatorId;
    }

    public void setOperatorId(String operatorId) {
        this.operatorId = operatorId;
    }

    public String getOperatorInfo() {
        return operatorInfo;
    }

    public void setOperatorInfo(String operatorInfo) {
        this.operatorInfo = operatorInfo;
    }

    public String getRemoteAddr() {
        return remoteAddr;
    }

    public void setRemoteAddr(String remoteAddr) {
        this.remoteAddr = remoteAddr;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getSubAction() {
        return subAction;
    }

    public void setSubAction(String subAction) {
        this.subAction = subAction;
    }

    /**
     * When detail is null, we just construct a simple info.
     * Format is: "$Action $Category: %Change.keyword"
     */
    @JsonIgnore
    public String getPrettyDetail() {
        if (StringUtils.isBlank(detail)) {
            String keyword = changes != null && !changes.isEmpty() ?
                    changes.get(0).getKeyword() : "";

            CategoryEnum ctg = CategoryEnum.UNKNOWN;
            if (category != null) {
                ctg = Enums.getIfPresent(CategoryEnum.class, category).or(CategoryEnum.UNKNOWN);
            }
            return String.format("%s %s: %s",
                    StringUtils.capitalize(StringUtils.lowerCase(action)),
                    ctg.getName(),
                    keyword);
        }
        return detail;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public String getAccountId() {
        return accountId;
    }

    public void setAccountId(String accountId) {
        this.accountId = accountId;
    }

    public String getAccountInfo() {
        return accountInfo;
    }

    public void setAccountInfo(String accountInfo) {
        this.accountInfo = accountInfo;
    }

    public List<Change> getChanges() {
        return changes;
    }

    public void setChanges(List<Change> changes) {
        this.changes = changes;
    }

    public Date getLogTime() {
        return logTime;
    }

    public void setLogTime(Date logTime) {
        this.logTime = logTime;
    }

    public Date getOpStartTime() {
        return opStartTime;
    }

    public void setOpStartTime(Date opStartTime) {
        this.opStartTime = opStartTime;
    }

    public Date getOpEndTime() {
        return opEndTime;
    }

    public void setOpEndTime(Date opEndTime) {
        this.opEndTime = opEndTime;
    }

    @JsonIgnore
    public String getSimpleInfo() {
        String detail = getPrettyDetail();
        return detail.length() > 50 ? detail.substring(0, 50) + "..." : detail;
    }

    @JsonIgnore
    public boolean hasDetail() {
        return StringUtils.isNotBlank(detail);
    }

    @JsonIgnore
    public String toString() {
        return getSimpleInfo();
    }

    public boolean isWriteRecord() {
        return writeRecord;
    }

    public void setWriteRecord(boolean writeRecord) {
        this.writeRecord = writeRecord;
    }

    public String getTraceId() {
        return traceId;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }

    public String getOperatorRole() {
        return operatorRole;
    }

    public void setOperatorRole(String operatorRole) {
        this.operatorRole = operatorRole;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}
